/*
  History
   2009-07-23 : 增加 toDigitLowerCase(String) 把全形的數字轉成半形的數字字串。
*/
package idv.jieh.commons.util;

import java.util.*;

public class DataAnalysis extends idv.jieh.commons.comm.BasicClass {

  /**
   * 把傳入的陣列轉換成字串後回傳。<p>
   * 產生的字串通常用於 SQL 語法中 update 或是 insert 的 (data,data,…)<br>
   * 把陣列 cols 中每個元素以逗點分隔，如果 sqm = true 則加上單引號，
   * 如果 brackets = true 則加上括弧後回傳。
   * @param data 要被處理的資料。
   * @param sqm 是否加上單引號。
   * @param brackets 是否加左右括號。
   * @return 處理完成的 StringBuilder。
   * @see collection2string
   */
  public static StringBuilder array2string(String[] data, boolean sqm, boolean brackets){
    return collection2string(array2vector(data), sqm, brackets);
  }

  /**
   * 把傳入的陣列轉換成字串後回傳。<p>
   * 產生的字串通常用於 SQL 語法中 update 或是 insert 的 (data,data,…)<br>
   * 把陣列 cols 中每個元素以逗點分隔，如果 sqm = true 則加上單引號，
   * 如果 brackets = true 則加上括弧後回傳。
   * @param cols 要被處理的資料。
   * @param sqm 是否加上單引號。
   * @param brackets 是否加左右括號。
   * @return 處理完成的 StringBuilder。
   * @see array2string
   */
  public static StringBuilder collection2string(Collection cols, boolean sqm, boolean brackets) {
    String delim = sqm?"','":",";
    StringBuilder r = new StringBuilder();
    for(Object data : cols) r.append(delim).append(data);
    r.delete(0, sqm?2:1);
    if(sqm) r.append("'");
    if(brackets) addBrackets(r);
    return r;
  }

  public static String[] collection2array(Collection <String>cols){
    int s = cols.size();
    String[] strings = new String[s];
    Object[] source = cols.toArray();
    for(int i=0; i<s; i++){
      strings[i] = source[i].toString();
    }
    return strings;
  }

  /**
   * 替字串加上左右括弧。<p>
   * @param sb 來源資料。
   * @return 加上括弧的 StringBuilder。
   */
  public static StringBuilder addBrackets(StringBuilder sb){
    return sb.insert(0, "(").append(")");
  }

  /**
   * 替數字前面補零，輸出固定位數的數值。<p>
   * 例如輸入 <code>numFormat(2, 4)</code> 輸出為：0002。
   * @param num 要處理的數字。
   * @param size 總長度。
   * @return 傳回需要的數字格式。
   */
  public static String numFormat(int num, int size) {
    String s = "";
    for (int i = 0; i < size; i++) s += "0";
    java.text.DecimalFormat f = new java.text.DecimalFormat(s);
    return f.format(num);
  }

  /**
   * 判斷傳入的字串如果是"0"，就傳回空字串，否則將原字串傳回。
   * @param s 要被判斷的字串。
   * @return 經處理過後的字串。
   */
  public static String trimZero(String s) {
    return Integer.parseInt(s) == 0 ? "" : s;
  }

  /**
   * 判斷字串是否為空值，如果是的話就傳回空字串。
   * @param strs 要被判斷的字串。
   */
  public static void trimNull(String ...strs) {
    for (int i = 0, l = strs.length; i < l; i++) strs[i] = trimNull(strs[i]);
  }

  /**
   * 判斷字串是否為空值，如果是的話就傳回空字串。
   * @param s 要被判斷的字串。
   * @return 傳回原來的字串或空字串。
   */
  public static String trimNull(String s) {return s == null ? "" : s.trim(); }

  /**
   * 將字串陣列轉為動態陣列(<code>java.util.Vector</code>)。<p>
   * @param s 要轉換的字串陣列。
   * @return 回傳轉換完成的陣列。
   */
  public static Vector array2vector(String[] s) { return new Vector(Arrays.asList(s));}

  /**
   * 將 <code>Enumeration Ojbect</code> 轉換成 <code>Vector Object</code> 後傳回。
   * @param src 需要被處理的 <code>Enumeration Ojbect</code>
   * @return 處理完成的 <code>Vector Object</code>
   */
  public static Vector enumeration2vector(Enumeration src) {
    Vector v = new Vector();
    while (src.hasMoreElements()) v.addElement(src.nextElement());
    return v;
  }

  /**
   * 字串切割[1]。<p>
   * 將字串以<b>逗號</b>分隔成一個 <code>Vector</code> 後傳回。<br>
   * <font color="#FF0000"><b>
   * **請改用 VectorMaker Object 所提供的 Method
   * </b></font>
   * @param s 要被分解的字串。
   * @return 傳回已經分隔一個 Vector 。
   */
  public static Vector string2vector(String s) { return string2vector(s, ","); }

  /**
   * 將字串切割成字串陣列。<p>
   * 「要處理的字串」傳入，然後依據分割字串，分割成字元陣列。
   * @param string 要處理的字串。
   * @param delim 分割字串。
   * @return 傳回已經分割完成的字串陣列。
   */
  public static String[] string2array(String string, String delim) {
    java.util.StringTokenizer st = new java.util.StringTokenizer(string, delim);
    int size = st.countTokens();
    String[] r = new String[size];
    for (int i = 0; i < size; i++) r[i] = st.nextToken();
    return r;
  }

  /**
   * 字串切割[2]。<p>
   * 將字串按照使用者指定的分隔字元，解譯成一個 <code>Vector</code> 後傳回。<br>
   * <font color="#FF0000"><b>
   * **請改用 VectorMaker Object 所提供的 Method
   * </b></font>
   * @param s 要被分解的字串。
   * @param delim 指定字串中的分隔字元。
   * @return 傳回一個已經分隔完畢的 Vector 。
   */
  public static Vector string2vector(String s, String delim) {
    StringTokenizer st = new StringTokenizer(s, delim);
    Vector vct = new Vector(st.countTokens());
    while (st.hasMoreTokens()) vct.addElement(st.nextToken().trim());
    return vct;
  }

  /**
   * 字串轉陣列的加強版。<p>
   * <code>idv.jieh.commons.util.DataAnalysis#string2array(String, String)</code>
   * 如果在分隔字元中間為空字串的話，該方法將會忽略不處理。
   * 而這個方法會將空字串的部分也轉為陣列的元素之一。
   * @param composite 要處理的字串。
   * @param delim 指定字串中的分隔字元。
   * @return 傳回已經分割完成的字串陣列。
   */
  public static String[] split(String composite, String delim) {
    ArrayList components = new ArrayList();
    composite = trimNull(composite);
    // 會造成 \t 被清空而無法正確拆解
//    delim = trimNull(delim);

    StringTokenizer tok = new StringTokenizer(composite, delim, true);
    boolean previousTokenWasDelim = true;
    while (tok.hasMoreTokens()) {
      String thisTok = tok.nextToken();
      if (thisTok.equals(delim)) {
        if (previousTokenWasDelim) components.add("");
        previousTokenWasDelim = true;
      } else {
        components.add(thisTok);
        previousTokenWasDelim = false;
      }
    }
    if (composite.endsWith(delim)) components.add("");

    int size = components.size();
    String[] ret = new String[size];
    for (int i = 0; i < size; i++) ret[i] = (String) components.get(i);

    return ret;
  }

  /**
   * 字串替換。<p>
   * 將「輸入字串」中<b>所有符合</b>「被替換字串」的部分全部換成「替換字串」。
   * @param str 輸入字串，將要處理的字串。
   * @param oStr 被替換字串，在「輸入字串」中要被替換的字串。
   * @param nStr 替換字串，將找到<b>所有符合</b>的「被替換字串」轉成「替換字串」。
   * @return String 處理完的字串。
   */
  public static String replace(String str, String oStr, String nStr) {
    StringBuilder sb = new StringBuilder(str);
    int fromIdx = 0;
    int oknife = oStr.length();
    int nknife = nStr.length();
    while (true) {
      int idx = sb.indexOf(oStr, fromIdx);
      if (idx == -1) return sb.toString();
      sb.replace(idx, idx + oknife, nStr);
      fromIdx = idx + nknife;
    }
  }

  /**
   * 判斷字串中是否都是數字。<p>
   * 如果是的話就回傳 true，否則就傳回 false。
   * @param s 要被判斷的字串。
   * @return boolean true：全部為數字，false：字串中有非數字字元。
   */
  public static boolean isDigit(String s) {
    char[] c = s.toCharArray();
    for (int i=0, l=c.length; i<l; i++)
      if (!Character.isDigit(c[i])) return false;
    return true;
  }

  /**
   * 判斷字串是否全部是文字，不含數字和特殊字元。<p>
   * 如果是的話就回傳 true，否則就傳回 false。
   * @param s 要被判斷的字串。
   * @return boolean true：全部為文字，false：字串中還有數字或特殊字元。
   */
  public static boolean isLetter(String s) {
    char[] c = s.toCharArray();
    for (int i=0, l=c.length; i<l; i++)
      if (!Character.isLetter(c[i])) return false;
    return true;
  }

  /**
   * 判斷字串是否不含特殊字元。<p>
   * 如果是的話就回傳 true，否則就傳回 false。
   * @param s 要被判斷的字串。
   * @return boolean true：不含特殊字元；false：字串中有特殊字元。
   */
  public static boolean isLetterOrDigit(String s) {
    char[] c = s.toCharArray();
    for (int i=0, l=c.length; i<l; i++) {
      if (!Character.isLetterOrDigit(c[i])) return false;
    }
    return true;
  }

  /**
   * 判斷字串陣列中是否有空字串或空值，如果偵測有其中一項，即回傳 false，全部都有值即回傳 true。
   * @param strs String[]
   * @return boolean
   */
  public static boolean isEmpty(String... strs){
    if(strs == null) return true;
    for(String s : strs){
      if(trimNull(s).length() == 0) return true;
    }
    return false;
  }

  /**
   * 計算字串陣列中有多少有值的元素。<P>
   * @param strs String[]
   * @return int
   */
  public static int countNotEmpty(String... strs){
    int r = 0;
    if(strs == null) return r;
    for(String s : strs){
      if(trimNull(s).length() > 0) r++;
    }
    return r;
  }

  public static String toDigitLowerCase(String s){
    return numFormat(Integer.parseInt(s), s.length());
  }

  public static void main(String ...args) {
    String[] s = {"", "ab123", "! ", "中文"};

    int l = s.length;
    for(int i=0; i<l; i++){
      System.out.println("isDigit - " + s[i] + ":" + DataAnalysis.isDigit(s[i]));
      System.out.println("isLetterOrDigit - " + s[i] + ":" + DataAnalysis.isLetterOrDigit(s[i]));
    }

    String[] strs = {"a", "b", "c"};
    String[] str_null = {"a", "b", "c", null};
//    trimNull(strs);
    System.out.println(strs[0]);
    System.out.println(strs[1]);
    System.out.println(strs[2]);
    Vector v = DataAnalysis.array2vector(strs);

    System.out.println(DataAnalysis.toDigitLowerCase("０００００５４５３１"));

    String[] ns = DataAnalysis.collection2array(v);

    System.out.println("numFormat test : " + numFormat(5, 3));
  }

} // end class DataAnalysis
